﻿import axios from "axios";
import store from "./store.js";
import mycode from "./my-encode.js";
import {
  defineComponent,
  compile,
  toRaw,
  reactive,
  createVNode,
  render,
} from "vue";
import mydate from "./mydate.js";
import _Utils from "./Utils.js";
import { MyDlgManager } from "./main.js";
import { process as RptPlugin, getRptActionAndParams } from "./PluginReport.js";
import { process as UploadPlugin } from "./PluginUpload.js";
import { process as SpeechPlugin } from "./PluginSpeech.js";
import { console } from "./other/vuedraggable/util/console.js";

const importFunc = new Function("url", `return import(url);`);

axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
axios.defaults.retry = 2;

function kebabToPascal(str) {
  return str
    .split("-")
    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
    .join("");
}

function pascalToKebab(str) {
  return str.replace(/([A-Z])/g, (match) => "-" + match.toLowerCase());
}

// 添加请求拦截器
axios.interceptors.request.use(
  function (config) {
    config.withCredentials = true;
    config.headers["Content-Type"] = "application/json;charset=UTF-8";
    if (
      config.data &&
      typeof config.data == "string" &&
      config.data.startsWith("{") &&
      config.data.endsWith("}")
    ) {
      config.data = JSON.parse(config.data);
    }
    if (
      store.debug != true &&
      (!config.data || typeof config.data == "object")
    ) {
      let data = { ...config.data };
      config.data = "__VIEWSTATE_=" + mycode.encode(data);
      config.headers["Content-Type"] =
        "application/x-www-form-urlencoded;charset=utf-8";
    }
    if (store.TokenName && store[store.TokenName]) {
      config.headers[store.TokenName] = store[store.TokenName];
    }
    if (store.JWTToken) {
      config.headers["Authorization"] = `Bearer ${store.JWTToken}`;
    }
    config.timeout = 3 * 60 * 1000;
    return config;
  },
  function (error) {
    throw error;
  }
);

/**
 * Asp.net mvc 返回的json数据中， 有可能有$id, $ref情形， $ref对象指向引用对象id，要替换成实际引用对象
 */
function parseAspNetRef(obj, dic) {
  dic = dic || [];
  Object.keys(obj).forEach((key) => {
    let vobj = obj[key];
    if (vobj && typeof vobj == "object") {
      if (vobj.$id) {
        dic[parseInt(vobj.$id)] = vobj;
      } else if (vobj.$ref) {
        obj[key] = dic[parseInt(vobj.$ref)];
      }
      parseAspNetRef(vobj, dic);
    }
  });
  return obj;
}

// 添加响应拦截器
axios.interceptors.response.use(
  function (response) {
    var res = response.data;

    const { code, data, message } = response?.data;
    if (code && message) {
      if (code == 0 || code == 200) {
        response.data = data;
        return response;
      } else if (message && typeof message == "string") {
        throw message;
      }
    }

    if (typeof res == "string") {
      if (response.request.responseType == "text") {
        return res;
      }
      try {
        res = JSON.parse(res);
      } catch {}

      if (typeof res == "string") {
        if (res.startsWith("OK")) {
          response.data = res;
          return response;
        }
        throw res;
      }
    }
    // 兼容返回方式： Result.GetMessageAndId
    if (
      res.ID != undefined &&
      res.Message &&
      typeof res.Message == "string" &&
      !res.Message.startsWith("OK")
    ) {
      res.Success = false;
    }

    if (res.extData) {
      res = mycode.decode(res.extData);
    }
    if (res.Success == false && res.Message) {
      throw res.Message;
    }

    if (res.success == false && res.message) {
      throw res.message;
    }

    if ((res.Success == true || res.success == true) && res.Data) {
      response.data = res.Data;
      return response;
    }

    res.pageSize = res.pageSize || res.PageSize;
    res.pageIndex = res.pageIndex || res.PageIndex;
    res.totalCount = res.totalCount || res.TotalCount;
    res.pageCount = res.pageCount || res.PageCount;
    res.records = res.records || res.Records;
    res.sumRow = res.sumRow || res.SumRow;

    delete res.PageSize;
    delete res.PageIndex;
    delete res.TotalCount;
    delete res.PageCount;
    delete res.Records;
    delete res.SumRow;

    if (!res.pageSize == undefined) {
      delete res.pageSize;
    }
    if (!res.pageIndex == undefined) {
      delete res.pageIndex;
    }
    if (res.totalCount == undefined) {
      delete res.totalCount;
    }
    if (!res.pageCount == undefined) {
      delete res.pageCount;
    }
    if (!res.records == undefined) {
      delete res.records;
    }
    if (!res.sumRow == undefined) {
      delete res.sumRow;
    }

    if (res.ExtensionData) {
      delete res.ExtensionData;
    }
    if (res.Fields && res.Fields.length > 0) {
      var records = [];
      var rows = JSON.parse(res.Rows);
      for (var ix = 0; ix < rows.length; ix++) {
        var row = rows[ix];
        var obj = {};
        for (var iy = 0; iy < res.Fields.length; iy++) {
          obj[res.Fields[iy]] = row[iy];
        }
        records.push(obj);
      }
      delete res.Fields;
      delete res.Rows;
      res.records = records;
    } else if (res.Data && res.Data.length > 0) {
      res.records = JSON.parse(res.Data);
    }
    delete res.Data;
    delete res.ExtensionData;
    delete res.PageSize;
    delete res.PageIndex;
    delete res.TotalCount;
    delete res.PageCount;

    response.data = parseAspNetRef(res);
    return response;
  },
  function (error) {
    const { code, message } = error.response?.data;
    if (code && message) {
      throw message;
    }
    if (error.response || error.code != "ERR_NETWORK") {
      throw error;
    }
    //网络连接不上
    var config = error.config;
    config.__retry = config.__retry || 0;

    if (config.__retry < config.retry) {
      config.__retry++;
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(axios(config));
        }, 1000);
      });
    } else {
      // return $msg.confirm("网络连接失败，是否重试？").then(res=>{
      //     var config = error.config;
      //     config.__retry = 1;
      //     return axios(config);
      // }).catch(e=>{
      //     throw error;
      // });

      throw error;
    }
  }
);

// window.addEventListener("unhandledrejection", event => {
//     /* 你可以在这里添加一些代码，以便检查
//        event.promise 中的 promise 和
//        event.reason 中的 rejection 原因 */
//     console.log(event)
//     event.preventDefault();
// }, false);
class Server {
  constructor() {
    this._cache = {};
    this._lastCall = null;
  }

  getUrl(action) {
    if (store.getAction) {
      action = store.getAction(action);
    } else if (store.api_action) {
      if (action.startsWith("../")) {
        action = action.substr(3);
      }
      action = store.api_action + action;
    }
    return action;
  }

  async cache_call(action, data, el) {
    let key =
      action +
      (!data
        ? ""
        : typeof data == "object"
        ? JSON.stringify(data)
        : String(data));
    let val = this._cache[key];
    if (val) {
      return val;
    }
    val = sessionStorage.getItem(key);
    if (val) {
      val = JSON.parse(val);
      this._cache[key] = val;
      return val;
    }

    this._cache[key] = this._call(action, data, el).then((res) => {
      sessionStorage.setItem(key, JSON.stringify(res));
      return res;
    });
    return this._cache[key];
  }

  call(action, data, el) {
    let key =
      action +
      (!data
        ? ""
        : typeof data == "object"
        ? JSON.stringify(data)
        : String(data));
    //1000毫秒（1秒钟内多次调用同一个请求，只实际调用一次
    if (this._lastCall && this._lastCall.key == key) {
      if (this._lastCall._promise) {
        //前一个请求正在执行
        return this._lastCall._promise;
      }
      if (new Date().getTime() - this._lastCall.time <= 1000) {
        return new Promise((resolve, reject) => {
          if (this._lastCall.result) {
            resolve(this._lastCall.result);
          }
          if (this._lastCall.error) {
            reject(this._lastCall.error);
          }
        });
      }
    }
    var promise = this._call(action, data, el)
      .then((res) => {
        this._lastCall = {
          key: key,
          result: res,
          time: new Date().getTime(),
        };
        return res;
      })
      .catch((e) => {
        this._lastCall = {
          key: key,
          error: e,
          time: new Date().getTime(),
        };
        throw e;
      });
    this._lastCall = {
      key: key,
      _promise: promise,
      time: new Date().getTime(),
    };
    return promise;
  }

  _call(action, data, el) {
    el = el || window._lucas_loading_el;

    action = this.getUrl(action);
    var callBack = null;
    if (typeof el == "function") {
      callBack = el;
      el = null;
    }

    var promise = new Promise((resolve, reject) => {
      el =
        el ||
        document.querySelector("#loading") ||
        document.querySelector("#loginForm") ||
        document.querySelector("#routerView") ||
        document.querySelector("#app");

      var loading = $msg.showLoading("正在加载...", el);
      axios
        .post(action, data)
        .then((res) => {
          if (typeof res.data == "string") {
            if (res.data.startsWith("OK")) {
              return res.data;
            } else {
              reject(res.data);
            }
          }
          if (
            typeof res.data == "object" &&
            res.data.Message &&
            typeof res.data.Message == "string" &&
            res.data.Message.indexOf("登录") != -1
          ) {
            reject(res.data.Message);
          }
          return res.data;
        })
        .then((res) => {
          resolve(res);
        })
        .catch((e) => {
          reject(e);
        })
        .finally(() => {
          if (loading) {
            loading.close();
          }
        });
    });

    if (callBack) {
      promise.then((res) => {
        callBack(res);
      });
    }
    return promise;
  }

  ping(action) {
    //不显示loading, 不影响界面显示
    action = this.getUrl(action);
    return axios.post(action).catch((e) => e);
  }

  getUserInfo() {
    return this.call("/Common/GetUserInfo", {}).then((res) => {
      store.user = res;
      store.hasLogin = true;
      return res;
    });
  }

  login(loginName, passwd) {
    return this.call("/Common/Login", {
      login_name: loginName,
      password: passwd,
    }).then((res) => {
      store.user = res;
      store.hasLogin = true;
      return res;
    });
  }

  logout() {
    return this.call("/Common/Logout")
      .then((res) => {
        store.user = {};
        store.hasLogin = false;
        store.token = "";
        return true;
      })
      .catch(() => {
        return false;
      });
  }

  async getAction(entityName, action) {
    let tb = await this.getDM(entityName);

    let callCfg = store.$mbh5 ? tb.call_h5 || tb.call : tb.call_pc || tb.call;
    if (typeof callCfg == "function") {
      callCfg = callCfg.call(tb);
    }
    if (callCfg && action in callCfg) {
      return callCfg[action];
    }
    return `/${entityName}/${action}`;
  }

  proceComputedRecords(tbname, res) {
    //处理计算字段的结果
    if (Array.isArray(res.records) && res.records.length > 0) {
      return this.getDM(tbname).then((tb) => {
        tb.columns
          .filter((p) => p.get && typeof p.get == "function")
          .forEach((field) => {
            res.records.forEach((row) => {
              row[field.code] = field.get.call(row);
            });
          });
        return res;
      });
    }
    return res;
  }

  proceComputedRow(tbName, row) {
    return this.getDM(tbName).then((tb) => {
      tb.columns
        .filter((p) => p.get && typeof p.get == "function")
        .forEach((field) => {
          row[field.code] = field.get.call(row);
        });
      return row;
    });
  }

  async list(entityName, pageIndex, pageSize, search, el) {
    let action = await this.getAction(entityName, "list");
    var pm = {};
    if (store.search2) {
      //查询参数放入pms
      pm.pageIndex = pageIndex || 1;
      pm.pageSize = pageSize || 20;
      pm.order = search.order || "";
      pm.pms = { ...search };
      delete pm.pms["order"];
    } else {
      pm = search || {};

      if (search && search.FieldConditionArray) {
        delete search.FieldConditionArray;
      }
      let FieldConditionArray = [];
      if (search) {
        Object.keys(search).forEach((key) => {
          if (
            ["FieldConditionArray", "____key", "pageIndex", "pageSize"].indexOf(
              key
            ) == -1
          ) {
            let sval = search[key];
            if (sval != undefined) {
              let sitem = { Name: key, Value: sval, TypeOf: 1 };
              FieldConditionArray.push(sitem);
            } else {
              delete pm[key];
            }
          }
        });
      }
      if (FieldConditionArray.length > 0) {
        pm.FieldConditionArray = FieldConditionArray;
      }
      pm.pageIndex = pageIndex || 1;
      pm.pageSize = pageSize || 20;
    }
    let listCall = pm._cache == true ? this.cache_call : this.call;
    return listCall
      .apply(this, [action, pm, el])
      .then((res) => {
        if (res.dataList && !res.records) {
          res.records = res.dataList;
          delete res.dataList;
          if (!res.pageIndex) {
            res.pageIndex = pageIndex || 1;
          }
          if (!res.pageSize) {
            res.pageSize = pageSize || 10;
          }

          if (!res.pageCount && res.totalCount) {
            res.pageCount = Math.ceil(res.totalCount / res.pageSize);
          }
        }
        return res;
      })
      .then((res) => this.proceComputedRecords(entityName, res));
  }

  async getFile(url, cfg) {
    url = await this.getUrl(url);
    return axios.get(url, cfg).then((res) => res.data);
  }

  async get(entityName, id, el) {
    let action = await this.getAction(entityName, "get");

    return this.call(action, { id: id }, el).then((res) => {
      if (typeof res != "object") {
        $msg.notify("找不到数据", "error");
        throw "找不到数据";
      }
      return this.proceComputedRow(entityName, res);
    });
  }

  async add(entityName, entity, el) {
    let action = await this.getAction(entityName, "add");

    return this.call(action, entity, el);
  }

  async update(entityName, entity, el) {
    let action = await this.getAction(entityName, "update");

    return this.call(action, entity, el);
  }

  async delete(entityName, id, el, msg) {
    let action = await this.getAction(entityName, "delete");

    return $msg.confirm(msg || "确认删除吗", "warning").then(() => {
      return this.call(action, { id: id }, el);
    });
  }

  async doAction(entityName, action, pms, el) {
    let action2 = await this.getAction(entityName, action);

    return this.call(action2, pms, el);
  }

  async setStatus(entityName, id, status, el) {
    let action = await this.getAction("setStatus");
    return this.call(action, { id: id, status: status }, el);
  }

  batch(actions, pms, el) {
    return this.call("/Common/Batch", { actions, pms }, el);
  }

  _buildRules(tb) {
    if (!tb.columns) return;
    if (!tb.rules) {
      tb.rules = {};
    }
    for (let col of tb.columns) {
      if (!tb.rules[col.code]) {
        tb.rules[col.code] = [];
      }
      let rules = tb.rules[col.code];
      if (col.required == true || typeof col.required == "string") {
        let rule = rules.find((p) => p.required == true);
        if (!rule) {
          let tp = undefined;
          switch (col.type.toLowerCase()) {
            case "string":
            case "text":
              tp = "string";
              break;
            case "bool":
            case "boolean":
              tp = "boolean";
              break;
            case "int":
              tp = "integer";
              break;
            case "array":
              tp = "array";
              break;
            case "date":
            case "datetime":
            case "time":
              tp = "date";
              break;
            case "object":
              tp = "object";
              break;
            case "number":
            case "number2":
            case "number4":
              tp = "number";
              break;
          }
          rule = {
            type: tp,
            required: true,
            trigger: "blur",
            message: `请录入${col.label}`,
          };
          if (col.type == "string") {
            rule.validator = (rule, value) => {
              return (
                value != undefined && value != null && String(value).length > 0
              );
            };
          }

          rules.push(rule);
        }
        //如果字段的可编辑属性是动态的， 对应的规则上也需要添加条件
        if (typeof col.editable == "string") {
          rule.vif = col.editable;
        }
        if (typeof col.required == "string") {
          rule.vif = col.required;
        }
        if (col.type == "bool") {
          rule.type = "boolean";
        }
      }

      if (col.regex) {
        let rule = rules.find((p) => p.type == "regexp");
        if (!rule) {
          let msg = col.message || `${col.label}格式不正确`;
          rule = { pattern: col.regex, message: msg, trigger: "blur" };
          if (typeof col.editable == "string") {
            rule.vif = col.editable;
          }
          if (typeof col.required == "string") {
            rule.vif = col.required;
          }
          rules.push(rule);
        }
      }
    }
  }

  proceMyCmp(cmpName, cmp, tbname) {
    if (typeof cmp == "object" && "template" in cmp) {
      let tpl = _Utils.parseUI2Template(cmp.template);
      let render = compile(tpl);
      cmp.render = render;
      delete cmp["template"];
    }

    //处理组件上定义的style
    if (cmp.style) {
      _Utils.attachStyle(`_cmp_${cmpName}`, cmp.style);
    }
    cmp = defineComponent(cmp);
    let gKey = `${tbname}_${cmpName}`;
    if (tbname == cmpName) {
      gKey = tbname;
    }
    if (_server.__app && !_server.__app.component(gKey)) {
      _server.__app.component(gKey, cmp);
    }
    return cmp;
  }

  loadComponent(cmpName) {
    if (_server.__app) {
      const name1 = kebabToPascal(cmpName);
      let cmp =
        _server.__app.component(cmpName) || _server.__app.component(name1);
      if (cmp) {
        return new Promise((resolve) => {
          resolve(cmp);
        });
      }
    }
    // let tb = this.getDM(cmpName);
    // return Promise.resolve(tb).then(cmp => {
    //     return this.proceMyCmp(cmpName, cmp, cmpName);
    // });
    return this.getDM(cmpName);
  }

  async _innerPrepareDM(tb, tbname) {
    if (typeof tb == "object" && "template" in tb) {
      this.proceMyCmp(tbname, tb, tbname);
      return tb;
    }

    tb.rules = tb.rules || {};

    let callCfg = store.$mbh5 ? tb.call_h5 || tb.call : tb.call_pc || tb.call;
    if (typeof callCfg == "function") {
      tb.call = callCfg.call(tb);
      delete tb["call_h5"];
    }

    if (tb && tb.ext && tb.ext.init0) {
      //模型第一时间执行
      let ret = tb.ext.init0.apply(this, [tb, store]);
      await Promise.resolve(ret);
    }

    let allPromise = [];

    //1、页面自定义组件
    if (tb.components && !tb._Components) {
      let keys = Object.keys(tb.components).map((key) => key);
      let cmps = Object.keys(tb.components).map((key) => {
        let cmpDefine = toRaw(tb.components[key]);

        if (typeof cmpDefine == "string") {
          return this.loadComponent(cmpDefine);
        }
        return this.proceMyCmp(key, cmpDefine, tbname);
      });
      //等待所有组件加载完成
      let items = await Promise.all(cmps);
      let _cmp = {};
      for (let i = 0; i < items.length; i++) {
        let cmp = items[i];
        let key = keys[i];
        _cmp[key] = cmp;

        if (_server.__app && !_server.__app.component(key)) {
          _server.__app.component(key, cmp);
        }
      }
      tb._Components = _cmp;
    }
    //2、字段处理
    if (tb && tb.columns) {
      if (typeof tb.columns == "object" && !Array.isArray(tb.columns)) {
        //columns对象定义方法
        let cols = [];
        Object.keys(tb.columns).forEach((p) => {
          let col = tb.columns[p];
          col.code = p;
          cols.push(col);
        });
        tb.columns = cols;
      }

      tb.columns.forEach((x) => {
        if (x.type == "bool") {
          x.type = "boolean";
        }
        if (x.tpl == true) {
          x.tpl = {
            control: x.control,
            props: { options: x.options, ...(x[x.control] || x.props) },
          };
        }
      });

      //2.1 options字符串扩展
      await _Utils.proceFieldsOptions(tb.columns);
    }

    //3、搜索条件中options选择框
    if (tb && tb.search) {
      if (typeof tb.search == "function") {
        tb.search = tb.search.apply(tb);
      }
      if (typeof tb.search == "string") {
        tb.search = tb.search.split(",").map((p) => {
          return { code: p };
        });
      }

      if (Array.isArray(tb.search)) {
        await _Utils.proceFieldsOptions(tb.search);
      }
    }

    if (tb.search_action && Array.isArray(tb.search_action)) {
      await _Utils.proceFieldsOptions(tb.search_action);
    }

    //4、Form中Items定义规范化，为了便宜书写，采用了不规范的书写方式
    this.formatFormItems(tb);

    //5、个性化调整模型
    if (tb && tb.ext && tb.ext.onDmDefineLoaded) {
      //模型加载以后，UI构造之前执行
      let ret = tb.ext.onDmDefineLoaded.apply(this, [tb, store]);
      //onDmDefineLoaded里面经常需要从服务器获得个性化配置对tb定义进行调整，
      //一定要等待调整完成以后，才能继续下面的工作
      await Promise.resolve(ret);
    }

    //6 为必填字段添加对应的规则
    //需要放到onDmDefineLoaded之后，onDmDefineLoaded里面可能修改了字段的required属性
    this._buildRules(tb);

    //必须等所有异步操作完成才能继续往下走
    if (allPromise.length > 0) {
      await Promise.all(allPromise);
    }
    return tb;
  }

  //
  formatFormItems(tb) {
    _Utils.formatFormItemsDefine(tb);
  }

  async prepareDM(tb, tbname) {
    //保证一个tb中_innerPrepareDM只执行一次
    if (!tb.__hasPrepareDM) {
      tb.__hasPrepareDM = this._innerPrepareDM(tb, tbname);
      await tb.__hasPrepareDM;
      RptPlugin(tb);
      if (tbname) {
        UploadPlugin(tb, tbname);
        await SpeechPlugin(tb, tbname);
      }
      //插件可能有生成字符串类型的options，需要再次处理
      await _Utils.proceFieldsOptions(tb.columns);
      if (Array.isArray(tb.search)) {
        await _Utils.proceFieldsOptions(tb.search);
      }
      if (tb.search_action && Array.isArray(tb.search_action)) {
        await _Utils.proceFieldsOptions(tb.search_action);
      }
    }
    return tb.__hasPrepareDM;
  }

  getDM(tbname) {
    return new Promise((resolve, reject) => {
      if (!this.dm) {
        this.dm = [];
      }
      let tb = this.dm[tbname];
      if (!tb && store.getDM) {
        tb = this.dm[tbname] = store.getDM(tbname);
      }
      if (!tb && store.dm_url) {
        let url = store.dm_url + tbname + ".js";
        tb = this.dm[tbname] = importFunc(url).then((m) => m.default);
      }

      Promise.resolve(tb)
        .then((tb1) => {
          if (!tb1) {
            let msg = `找不到DataModule:${tbname}`;
            $msg.error(msg);
            reject(msg);
            return;
          }
          if (!tb1.tbname) {
            tb1.tbname = tbname;
          }

          let tmp1 = this.prepareDM(tb1, tbname);
          Promise.resolve(tmp1).then(() => {
            resolve(reactive(tb1));
          });
        })
        .catch((e) => {
          console.log(e);
          reject(e);
        });
    });
  }
  //取字段值并格式化用于显示
  //colums是DM中tb的列定义
  getFieldValue(columns, field, row) {
    columns = columns || [];
    let fd = columns.filter((p) => p.code == field)[0];
    if (fd) {
      let val = row[field];
      if (val == undefined || val == null) {
        return "";
      }
      if (field.indexOf(".") != -1) {
        let sss = field.split(".");
        val = row;
        sss.forEach((ss) => {
          val = val[ss] || "";
        });
      }
      if (typeof val == "number" && val == 0) {
        val = "0";
      }
      if (
        (fd.control == "combo" || fd.control == "radio") &&
        fd.options &&
        Array.isArray(fd.options)
      ) {
        let pp1 = fd.options.filter((p) => p.value == val)[0];
        if (pp1) {
          val = pp1.label;
        }
      }
      if (
        val &&
        fd.format &&
        (fd.type == "date" || fd.type == "datetime" || fd.type == "time")
      ) {
        val = mydate.formatDate(val, fd.format);
      }
      //字段上定义了格式化函数
      if (fd.format && typeof fd.format == "function") {
        return fd.format.apply(this, [val, row]);
      }
      if (typeof val == "boolean") {
        return val ? "是" : "否";
      }
      return val;
    }
    return row[field] || "";
  }

  //用行(row)内容进行格式化输出
  dm_format(columns, row, format) {
    try {
      if (!format) return "";
      let ix = format.indexOf("${");
      if (ix == -1) return this.getFieldValue(columns, format, row);

      let str = format.replace(/\$\{([^}]+)\}/g, (t1, field) => {
        let ifx = field.indexOf(":");
        if (ifx == -1) {
          return this.getFieldValue(columns, field, row);
        } else {
          let fmt = field.substr(ifx + 1);
          field = field.substr(0, ifx);
          let val = this.getFieldValue(columns, field, row);
          if (val == "是") {
            return fmt.split(/[,，；;]/g)[0] ?? val;
          }
          if (val == "否") {
            return fmt.split(/[,，；;]/g)[1] ?? val;
          }
          let valDt = mydate.parseDate(val);
          if (valDt && valDt instanceof Date && fmt) {
            val = mydate.formatDate(valDt, fmt);
          }
          return val;
        }
      });
      return str;
    } catch (e) {
      console.log(e);
    }
  }

  $get(url, params) {
    url = this.getUrl(url);
    if (params) {
      location.href = url + "?__VIEWSTATE_=" + mycode.encode(params);
    } else {
      location.href = url;
    }
  }

  download(url, params, callback) {
    if (navigator.userAgent.indexOf("Windows") == -1) {
      this.$get(url, params);
      return;
    }
    var loading = $msg.showLoading("正在下载...");

    const action = this.getUrl(url);

    axios
      .post(action, params, { responseType: "blob" })
      .then((response) => {
        var fn = response.headers["content-disposition"];
        if (!fn) {
          //发生错误了， 错误信息成了blob
          response.data.text().then((text) => {
            $msg.error(text);
          });
          return;
        }
        fn = fn.replace("*=UTF-8''", "=");
        fn = fn.substr(fn.indexOf("filename=") + 9);
        fn = decodeURIComponent(fn);
        var blob = response.data;

        var a = document.createElement("a");
        a.download = fn;
        var url = window.URL || window.webkitURL;

        a.href = url.createObjectURL(blob);
        a.click();

        if (callback) {
          callback.apply(this, fn);
        }
      })
      .finally(() => {
        loading.close();
      });
  }

  downloadFile(url, filename) {
    var a = document.createElement("a");
    a.target = "_blank";
    if (filename) {
      a.download = filename;
    }
    a.href = url;
    a.click();
    a.remove();
  }

  upload(cfg) {
    cfg = cfg || {};
    if (!cfg.url) {
      cfg.url = store.UploadServer || "../Common/UploadFile";
    }

    cfg.url = this.getUrl(cfg.url);

    var me = this;
    return new Promise((resolve, reject) => {
      var inp = null;
      const inputID = "____input_file_upload_";
      inp = document.getElementById(inputID);
      if (!inp) {
        inp = document.createElement("input");
        inp.id = inputID;
        inp.type = "file";
      }
      inp.accept = cfg.accept || "*/*";
      inp.multiple = cfg.multiple || false;
      if (cfg.capture == true) {
        inp.capture = "";
      } else {
        inp.removeAttribute("capture");
      }
      inp.style = "display:none;";
      inp.onchange = function (e) {
        const files = e.target.files;
        if (!files || files.length == 0) return;

        const xhr = new XMLHttpRequest();

        var formData = new FormData();

        if (cfg.extData) {
          Object.keys(cfg.extData).forEach((key) => {
            formData.append(key, cfg.extData[key]);
          });
        }

        for (let i = 0; i < files.length; i++) {
          let file = files[i];
          formData.append(file.name, file, file.name);
        }

        var loading = $msg.showLoading("正在上传...");

        xhr.onerror = function error() {
          reject(xhr);
        };

        xhr.onload = function onload() {
          if (xhr.status < 200 || xhr.status >= 300) {
            reject(xhr.statusText);
            return;
          }
          var text = xhr.responseText || xhr.response;
          try {
            text = JSON.parse(text);
            if ("success" in text) {
              if (text.success == false) {
                reject(text.message);
                return;
              }
            }
          } catch {}

          if (typeof text == "string" && !text.startsWith("OK")) {
            reject(text);
            return;
          }
          resolve(text);
        };

        xhr.onloadend = function () {
          if (inp != null) {
            document.body.removeChild(inp);
            inp = null;
          }
          loading.close();
        };

        xhr.open("post", cfg.url, true);

        if ("withCredentials" in xhr) {
          xhr.withCredentials = true;
        }
        if (store.JWTToken) {
          xhr.setRequestHeader("Authorization", `Bearer ${store.JWTToken}`);
        }

        const headers = cfg.headers || {};

        for (const item in headers) {
          if (headers.hasOwnProperty(item) && headers[item] !== null) {
            xhr.setRequestHeader(item, headers[item]);
          }
        }
        xhr.send(formData);
      };
      inp.oncancel = function () {
        if (inp != null) {
          document.body.removeChild(inp);
          inp = null;
        }
        reject("cancel");
      };

      document.body.appendChild(inp);
      inp.value = null;
      inp.click();
    });
  }

  upload_new(cfg) {
    cfg = cfg || {};
    if (!cfg.url) {
      cfg.url = store.UploadServer || "../Common/UploadFile";
    }

    const url = $server.getUrl ? $server.getUrl(cfg.url) : cfg.url;

    return new Promise((resolve, reject) => {
      let inp = null;
      const inputID = "____input_file_upload_";
      inp = document.getElementById(inputID);
      if (!inp) {
        inp = document.createElement("input");
        inp.id = inputID;
        inp.type = "file";
      }
      inp.accept = cfg.accept || "*/*";
      inp.multiple = !!cfg.multiple;
      if (cfg.capture == true) {
        inp.capture = "";
      } else {
        inp.removeAttribute("capture");
      }
      inp.style = "display:none;";

      let removedWatchers = false;
      function removeCancelWatchers() {
        if (removedWatchers) return;
        removedWatchers = true;
        window.removeEventListener("focus", onReturnFromPicker, true);
        document.removeEventListener(
          "visibilitychange",
          onVisibilityChange,
          true
        );
      }
      function onReturnFromPicker() {
        setTimeout(() => {
          if (!inp) return;
          const hasFiles = inp.files && inp.files.length > 0;
          if (!hasFiles) {
            try {
              document.body.removeChild(inp);
            } catch (e) {}
            inp = null;
            removeCancelWatchers();
            reject("cancel");
          } else {
            removeCancelWatchers();
          }
        }, 1000);
      }
      function onVisibilityChange() {
        if (document.visibilityState === "visible") {
          onReturnFromPicker();
        }
      }

      inp.onchange = function (e) {
        removeCancelWatchers();
        const files = e.target.files;
        if (!files || files.length === 0) return;

        const xhr = new XMLHttpRequest();
        const formData = new FormData();

        if (cfg.extData) {
          Object.keys(cfg.extData).forEach((key) => {
            formData.append(key, cfg.extData[key]);
          });
        }

        for (let i = 0; i < files.length; i++) {
          const file = files[i];
          formData.append(file.name, file, file.name);
        }

        const loading =
          $msg && typeof $msg.showLoading === "function"
            ? $msg.showLoading("正在上传...")
            : { close: function () {} };

        xhr.onerror = function () {
          reject(xhr);
        };

        xhr.onload = function () {
          debugger;
          if (xhr.status < 200 || xhr.status >= 300) {
            reject(xhr.statusText);
            return;
          }
          let text = xhr.responseText || xhr.response;
          try {
            text = JSON.parse(text);
            if ("success" in text && text.success === false) {
              reject(text.message);
              return;
            }
          } catch (err) {}

          if (typeof text === "string" && !text.startsWith("OK")) {
            reject(text);
            return;
          }
          resolve(text);
        };

        xhr.onloadend = function () {
          if (inp != null) {
            try {
              document.body.removeChild(inp);
            } catch (e) {}
            inp = null;
          }
          if (loading && typeof loading.close === "function") {
            loading.close();
          }
        };

        xhr.open("post", url, true);

        if ("withCredentials" in xhr) {
          xhr.withCredentials = true;
        }
        if (store.JWTToken) {
          xhr.setRequestHeader("Authorization", "Bearer " + store.JWTToken);
        }

        const headers = cfg.headers || {};
        for (const item in headers) {
          if (
            Object.prototype.hasOwnProperty.call(headers, item) &&
            headers[item] !== null
          ) {
            xhr.setRequestHeader(item, headers[item]);
          }
        }
        xhr.send(formData);
      };

      window.addEventListener("focus", onReturnFromPicker, true);
      document.addEventListener("visibilitychange", onVisibilityChange, true);

      document.body.appendChild(inp);
      inp.value = null;
      inp.click();
    });
  }

  loadJS(url, tag) {
    if (!url) return;
    url = this.getUrl(url);
    return new Promise(function (resolve, reject) {
      if (tag) {
        if (tag in window) {
          resolve();
          return;
        }
      }

      let found = false;
      //防止一个页面多次引入同一个js文件
      for (let i = 0; i < document.scripts.length; i++) {
        var el = document.scripts[i];
        if (el.src.endsWith(url)) {
          var icount = 0;
          var handle = window.setInterval(() => {
            icount++;

            if (tag && tag in window) {
              window.clearInterval(handle);
              resolve();
              return;
            }
            if (el.dataset["loaded"] == "done") {
              window.clearInterval(handle);
              resolve();
              return;
            }
            if (icount > 1200) {
              //120秒以后还未加载完成，就不再继续检测
              window.clearInterval(handle);
            }
          }, 100);
          found = true;
          return;
        }
      }

      if (!found) {
        var script = document.createElement("script");
        script.type = url.endsWith(".mjs") ? "module" : "text/javascript";
        script.src = url;
        script.onload = () => {
          script.dataset["loaded"] = "done";
          resolve();
        };
        document.getElementsByTagName("head")[0].appendChild(script);
      }
    });
  }

  delay(ms = 200) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  string2rows(str) {
    return _Utils.string2rows(str);
  }

  encode(str) {
    return mycode.encode(str);
  }
}

const _server = new Server();

_server.getRptActionAndParams = getRptActionAndParams;

//默认自动加载MyDlgManager, 已经有太多地方依赖它，不再需要在用户代码中加载
Object.defineProperty(_server, "dlg", {
  get() {
    if (!this.__dlg) {
      var el = document.createElement("div");
      const vm = createVNode(MyDlgManager);
      let app = _server.__app;
      vm.appContext = app._context;
      render(vm, el);
      this.__dlg = vm.component.ctx;
    }
    return this.__dlg;
  },
  set(val) {
    this.__dlg = val;
  },
});

if (window) {
  window.addEventListener("unhandledrejection", (err) => {
    err = err?.reason || err;
    if (err && err != "cancel") {
      $msg.notify(err, "error");
    }
  });
}
export default _server;
